package ltd.bugs.cute.common.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ltd.bugs.cute.common.store.SimpleDataStore;

/**
 * 配置文件的加载工具类，支持多个配置文件的加载，加载之后缓存到SimpleDataStore中
 * 
 * @author zhengzhq
 *
 */
public class PropertyUtil {

  private static Logger logger = LoggerFactory.getLogger(PropertyUtil.class);
  // 框架的默认配置文件，有的话优先使用该文件的配置，类似struts2-default.properties
  public static final String CUTE_DEFAULT_CONFIGURATION = "cute-default.properties";

  /**
   * 获取框架的默认/全局配置
   * 
   * @param key
   * @param type
   * @return
   */
  public static <T> T getDefaultConfig(String key, Class<T> type, T defaultVal) {
    T value = getConfig(CUTE_DEFAULT_CONFIGURATION, key, type);
    if (value != null) {
      return value;
    }

    return defaultVal;
  }

  /**
   * 获取框架的默认/全局配置
   * 
   * @param key
   * @param type
   * @return
   */
  public static <T> T getDefaultConfig(String key, Class<T> type) {
    return getConfig(CUTE_DEFAULT_CONFIGURATION, key, type);
  }

  /**
   * 获取配置文件中的值
   * 
   * @param resourcePath 配置文件的路径，从classpath下扫描，比如
   *        resourcePath=cute-default.properties，那实际上是classes/cute-default.properties
   * @param key 要获取配置的key
   * @param type 返回的数据类型
   * @return
   */
  @SuppressWarnings("unchecked")
  public static <T> T getConfig(String resourcePath, String key, Class<T> type) {
    // 判断SimpleDataStore中是否存在
    if (!SimpleDataStore.contains(resourcePath)) {
      loadConfigurationFromResource(resourcePath);
    }

    Object value = SimpleDataStore.get(resourcePath, key);
    // 此处不抛出异常，由具体的业务实现来判断是否需要判断。例如像获取激活扩展节点就允许为null
    if (value == null) {
      return null;
    }

    if (type == Boolean.class) {
      return (T) new Boolean(value.toString());
    }

    if (type == Integer.class) {
      return (T) new Integer(value.toString());
    }

    if (type == Double.class) {
      return (T) new Double(value.toString());
    }

    if (type == Float.class) {
      return (T) new Float(value.toString());
    }
    return (T) value;
  }

  public static <T> T getConfig(String resourcePath, String key, Class<T> type, T defaultVal) {
    T value = getConfig(resourcePath, key, type);
    if (value == null) {
      value = defaultVal;
    }

    return value;
  }

  private static void loadConfigurationFromResource(String resourcePath) {
    synchronized (resourcePath.intern()) {
      // 再次确认
      if (SimpleDataStore.contains(resourcePath)) {
        return;
      }
      InputStream is = null;
      try {
        URL url = PropertyUtil.class.getClassLoader().getResource(resourcePath);
        if (url == null) {
          return;
        }

        logger.info("start load configuration from resource: " + resourcePath);
        is = url.openStream();
        Properties properties = new Properties();
        properties.load(is);

        for (Object key : properties.keySet()) {
          SimpleDataStore.put(resourcePath, key.toString(), properties.get(key));
        }
        logger.info("finish load configuration from resource: " + resourcePath);
      } catch (IOException e) {
        throw new IllegalStateException(
            "load configuration from resource: " + resourcePath + " error!", e);
      } finally {
        IOUtils.closeQuietly(is);
      }
    }
  }
}
